﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Diagnostics;
using Lon.Util;
using Lon.Data;
using Lon.IO;
using Lon.DataStore;
using System.IO;
using ProtoBuf;
using LonLog;

namespace Lon.Server
{
    public class AppServer 
    {
        public Dictionary<Socket, FrontServerNode> clientSocketDict = new Dictionary<Socket, FrontServerNode>();
        public Dictionary<int, FrontServerNode> clientDbmDict = new Dictionary<int, FrontServerNode>();



        NetNodeManager netNodeManager = new NetNodeManager();

        public NetNodeManager NetNodeManager
        {
            get { return netNodeManager; }
            set { netNodeManager = value; }
        }

        public String ServerName { get; set; }

        private String dbm = "BJF";

        private String severDbm = "AP1";



        public int Port = 7777;



        public int standByServerPort = 7779;

        public String standByServerIp;

        StandByServer standByServer;

        public StandByServer StandByServer
        {
            get { return standByServer; }
        }

        public AppServer(String dbm, String standByServerIp)
        {
            while (dbm.Length < 3) dbm = dbm.Insert(0, " ");
            this.dbm = dbm;

            this.standByServerIp = standByServerIp;
            this.InterfaceId = dbm[0] + (dbm[1] << 8) + (dbm[2] << 16);

        }

        IDataAccessService storeSevice;

        String dataStorePath;


        public AppServer()
        {
            String path = Path.Combine(PathHelper.GetApplicationPath(), "Server.ini");
            IniFile cfg = new IniFile(path);
            cfg.Load();
            this.dbm = cfg.GetString("应用服务器", "电报码");
            Port = cfg.GetInt("应用服务器", "端口号", Port);
            standByServerPort = cfg.GetInt("应用服务器", "主备机连接端口号", standByServerPort);
            standByServerIp = cfg.GetString("应用服务器", "备机IP地址");
            dataStorePath = cfg.GetString("存储", "文件夹"); 
            this.InterfaceId = dbm[0] + (dbm[1] << 8) + (dbm[2] << 16);
            netNodeManager.InterfaceId = this.InterfaceId;
            netNodeManager.LoadNetNodeFromFile(Path.Combine(dataStorePath, "StationCfg.ini"));
            foreach (NetNode node in netNodeManager.GetNodeList())
            {
                node.ConnectStatusChangeHandler += new EventHandler<ConnectStatusChangeEventArgs>(DoNodeStatusChange);
            }
           
            storeSevice = DataAccessSeriveFactory.GetService(null);


        }
        bool haveNodeStatusChange = false;
        public void DoNodeStatusChange(object obj, ConnectStatusChangeEventArgs e)
        {
            haveNodeStatusChange = true;
        }
        public void Start()
        {
            IPAddress ipAddr;
            if (String.IsNullOrEmpty(this.standByServerIp) || !IPAddress.TryParse(this.standByServerIp, out ipAddr))
            {
                this.standByServerIp = "";
            }
            this.standByServer = new StandByServer(this, standByServerIp, standByServerPort);

            this.standByServer.Start();


            Thread th = new Thread(new ThreadStart(StartListening));
            th.IsBackground = true;
            th.Start();
            Thread heartbeatThread = new Thread(new ThreadStart(HeartbeatProc));
            heartbeatThread.IsBackground = true;
            heartbeatThread.Start();
        }

        public String Dbm
        {
            get { return dbm; }
        }

        /// <summary>
        /// 对外接口Id
        /// </summary>
        public int InterfaceId
        {
            get;
            private set;
        }

        public void OutDebugMessage(String txt)
        {

        }

        public void StartListening()
        {
            IPAddress MyAllIP = new IPAddress(0);

            IPEndPoint ipe = new IPEndPoint(MyAllIP, Port);
            ThreadPool.SetMaxThreads(1000, 500);
            Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                listener.Bind(ipe);
                listener.Listen(1000);

                while (true)
                {
                    try
                    {
                        Socket s = listener.Accept();
                        var ep = s.RemoteEndPoint as IPEndPoint;
                        LogHelper.WriteLog("", LogType.Info,
                             String.Format("收到新连接{0}:{1}", ep.Address, ep.Port));
                        FrontServerNode sc = new FrontServerNode(s, this);
                        sc.Start();
                        this.clientSocketDict[s] = sc;

                    }
                    catch (Exception ex)
                    {
                        OutDebugMessage(ex.Message + ex.StackTrace);
                    }
                }
            }
            catch
            {
            }
        }//end StartListening

        public void HeartbeatProc()
        {
            while (true)
            {
                Thread.Sleep(1000);
                //SendStatusChange();
                ReadDayReport();
                PeriodCheck();
                SendHeartbeat();
              
            }
        }
   
        private void PeriodCheck()
        {
            List<NetNode> nodeList = this.NetNodeManager.GetNodeList();
            foreach (var node in nodeList)
            {
                node.PeriodCheck();
            }
        }

      
        private void SendStatusChange()
        {
            if (this.haveNodeStatusChange)
            {
                this.haveNodeStatusChange = false;
                DataFrame df = DataFrameFactry.CreateStatusFrame(this.InterfaceId, this.InterfaceId, netNodeManager.GetNodeList());
                List<NetNode> terminalNodes = netNodeManager.GetNodeList(NodeType.Terminal);
                SendDataFrame(terminalNodes, df);
                SendDataFrame(netNodeManager.GetNodeList(NodeType.MangerClient), df);
            }
           
        }

        private void SendDataFrame(List<NetNode> nodes, DataFrame df)
        {
            foreach (NetNode node in nodes)
            {
                node.SendDataFrame(df);
            }

        }

        int sendHeartbeatWaitCount = 0;
        private void SendHeartbeat()
        {
            sendHeartbeatWaitCount++;
            if (sendHeartbeatWaitCount < 5) return;
            sendHeartbeatWaitCount = 0;
            this.standByServer.SendHeartbeat();
            List<FrontServerNode> list = new List<FrontServerNode>(500);
            lock (clientSocketDict)
            {
                list.AddRange(clientSocketDict.Values);
            }
            for (int i = 0; i < list.Count; i++)
            {
                if (list[i] == null) continue;
                list[i].SendHeartbeat();
            }
        }


        private DateTime lastDayReadTime = DateTime.Now.Date;

        private List<NetNode> waitReportToReadList = new List<NetNode>();

        /// <summary>
        ///  每天一点之后读取前一天的日报表每秒读一个站
        /// </summary>
        int readDelayCount = 0;
        const int readDelayMax = 10; //设定每10查询一个站的模拟量报表,防止因网络满堵塞处理
        private void ReadDayReport()
        {
            if (lastDayReadTime.Date != DateTime.Now.Date && DateTime.Now.Hour > 1)
            {
                lastDayReadTime = DateTime.Now.Date;
                waitReportToReadList = netNodeManager.GetNodeList(NodeType.Station);
                return;
            }
            if (waitReportToReadList.Count > 0)
            {
                if (readDelayCount < readDelayMax)
                {
                    readDelayCount++;
                    return;
                }
                readDelayCount = 0;

                waitReportToReadList[0].QueryDayReport(DateTime.Now.AddDays(-1));
                waitReportToReadList.RemoveAt(0);
            }
        }


        /// <summary>
        /// 应用服务器最后一次通信时间
        /// </summary>
        private DateTime appSeverLastHeartbeatTime;


        private void DealAppSeverDataFrame(DataFrame df)
        {
            if (df.DataFrameFlag == DataFrameFlag.Heartbeat)
            {
                appSeverLastHeartbeatTime = DateTime.Now;
                return;
            }
            if (df.DataFrameFlag == DataFrameFlag.Data)
            {
                if (df.DstId == this.InterfaceId) return;
                FrontServerNode sc = null;
                lock (this.clientDbmDict)
                {
                    if (String.IsNullOrEmpty(df.DstDbm)) return;
                    if (!this.clientDbmDict.ContainsKey(df.DstId)) return;
                    sc = this.clientDbmDict[df.DstId];
                }
                if (sc == null) return;
                sc.SendMessage(df);

            }


        }


        public void SendToAppSever(DataFrame df)
        {

        }


        public void SendToBalance(DataFrame df)
        {
            this.standByServer.RealSend(df.Buf);
        }


        internal void RemoveClient(FrontServerNode stationClient)
        {
            lock (this.clientSocketDict)
            {
                if (this.clientSocketDict.ContainsKey(stationClient.ClientSocket))
                {
                    this.clientSocketDict.Remove(stationClient.ClientSocket);
                }
            }
            lock (this.clientDbmDict)
            {
                if (this.clientDbmDict.ContainsKey(stationClient.Id))
                {
                    this.clientDbmDict.Remove(stationClient.Id);
                }
            }
        }





        internal void Process(DataFrame df, IFrontServer frontServerNode)
        {
            NetNode csmNode = this.netNodeManager.GetNode(df.SrcId);
            if (csmNode == null)
            {
                csmNode = new NetNode();
                csmNode.Id = df.SrcId;
                csmNode.Dbm = df.SrcDbm;
                csmNode.InferfaceId = this.InterfaceId;
                csmNode.Ip = "";
                csmNode.Name = csmNode.Dbm;
               
            }
            if (csmNode.InferfaceId == 0)
            {
                csmNode.InferfaceId = this.InterfaceId;
            }
            
            if (df.DstId == this.InterfaceId
                &&df.MajorDataType== MajorDataType.NetStatus)
            {
                this.ProcessNetStatus(df,frontServerNode);
            }
            else if (df.IsCommand)
            {
                
            }


        }

        private void ProcessNetStatus(DataFrame df, IFrontServer frontServerNode)
        {
            if (df.IsCommand)
            {
                ProcessNetStatusCmd(df, frontServerNode);
            }
            else 
            {
                ProcessNetStatusData(df, frontServerNode);
            }
         

        }

        private void ProcessNetStatusData(DataFrame df, IFrontServer frontServerNode)
        {
            if (df.IsLonSelfFrame)
            {
                bool changFlag=false;
                MemoryStream ms=new MemoryStream(df.DataBuf);
                List<NetNodeStateRec> nodeStateRecList = Serializer.Deserialize<List<NetNodeStateRec>>(ms);
                List<NetNode> nodeList = this.NetNodeManager.GetNodeList();
                foreach (var rec in nodeStateRecList)
                {
                    if (rec.Id <= 0)
                    {
                        continue;
                    }
                  
                    NetNode node = nodeList.Find((NetNode n) => n.Id == rec.Id);
                    
                    if (node == null)
                    {
                        node = new NetNode();
                        node.Ip=rec.IpAddr;
                        node.Id=rec.Id;
                     
                        this.NetNodeManager.AddNode(node);
                     
                    }
                    if(rec.IpAddr!=node.Ip)
                    {
                        node.Ip = node.Ip;
                        changFlag = true;
                    }
                    if (rec.State == true)
                    {
                        node.Feed();
                    }
                    node.ParentServer = frontServerNode;
                }
                if (changFlag == true)
                {
                    this.NetNodeManager.Save(Path.Combine(dataStorePath, "StationCfg.ini"));
                }
               
            }
            else
            {
                if (df.DataBuf.Length < 4)
                {
                    return;
                }
                MemoryStream ms = new MemoryStream(df.DataBuf);
                BinaryReader br = new BinaryReader(ms);
                int count = br.ReadInt32()/4;
                int byteCalcCount=(df.DataBuf.Length - 4) / 4;//通过字节数计算
                count = (count <= byteCalcCount) ? count : byteCalcCount;
                  List<NetNode> nodeList = this.NetNodeManager.GetNodeList();
                for (int i = 0; i < count; i++)
                {
                    int val = br.ReadInt32();
                    int id = val & 0xffffff;
                    int state = val >> 24;
                    if (state == 0)
                    {
                        continue;
                    }
                    NetNode node = nodeList.Find((NetNode n) => n.Id == id);
                    if (node == null)
                    {
                        node = new NetNode();
                        node.Ip = "";
                        node.Id = id;
                        this.NetNodeManager.AddNode(node);
                    }
                    node.Feed();
                }


            }
        }

        private void ProcessNetStatusCmd(DataFrame df, IFrontServer frontServerNode)
        {
            if (df.IsLonSelfFrame)
            {
                List<NetNode> nodeList = this.NetNodeManager.GetNodeList();
                byte[] ret = PackLonNodeStatusPackage(nodeList);
                DataFrame dst = new DataFrame(df.SrcId, this.InterfaceId, DataDir.SeverAck, false, false, true, 0x23, 0, ret);
                frontServerNode.SendMessage(dst);
            }
            else
            {
                List<NetNode>  nodeList = this.NetNodeManager.GetNodeList();
            
                byte[] ret = PackNodeStatusPackage(nodeList);

                DataFrame dst = new DataFrame(df.SrcId,this.InterfaceId, DataDir.SeverAck, false, false, false, 0x23, 0, ret);
                frontServerNode.SendMessage(dst);
 
            }
        }

        private byte[] PackNodeStatusPackage(List<NetNode> dbmList)
        {
            byte[] buf = new byte[8 + (dbmList.Count * 4)];
            BinaryWriter bw = new BinaryWriter(new MemoryStream(buf));
            bw.Write((int)((dbmList.Count) * 4));
        
            foreach (NetNode node in dbmList)
            {
                int id = node.Id;
                bw.Write(id);
                bw.BaseStream.Seek(-1, SeekOrigin.Current);
                byte status = node.ConnectedState ? ((byte)1) : ((byte)0);
                bw.Write(status);
            }
            return buf;

        }
        private byte[] PackLonNodeStatusPackage(List<NetNode> dbmList)
        {
            List<NetNodeStateRec> list = new List<NetNodeStateRec>();

            foreach (NetNode node in dbmList)
            {
                NetNodeStateRec rec = new NetNodeStateRec();
                rec.Id = node.Id;
              
                rec.IpAddr = node.Ip.ToString();
                rec.NodeType = node.NodeType;
                rec.State = true;


            }
            MemoryStream ms = new MemoryStream();
            Serializer.Serialize<List<NetNodeStateRec>>(ms, list);


            return ms.ToArray();

        }
    }



}
